<template>
	<div class="wind-stepper">
		<div
			class="wind-stepper__minus"
			:class='{
				"is-disabled":minusDisabled,
			}'
			@click="onStepperBtnClick('minus')"
		>-</div>
		<w-input-number
			ref="inputRef"
			:value="currentValue"
			:disabled="disabled"
			:readonly="readonly"
			:placeholder="placeholder"
			:integer="integer"
			:max="max"
			:min="min"
			:pointSize="pointSize"
			:intLength="intLength"
			:positive="positive"
			class="stepper-input"
			@change="onChange"
			@blur="onBlur"
			@focus="onFocus"
		></w-input-number>
		<div
			class="wind-stepper__plus"
			:class='{
				"is-disabled":plusDisabled,
			}'
			@click="onStepperBtnClick('plus')"
		>+</div>
	</div>
</template>
<script lang="ts">
/**
 * Stepper by shang 2022/9/20
 * @desc Stepper 数字步进器
 * @param {value}  [Number, String] - 输入框值
 * @param {integer}  [Boolean] - 是否int
 * @param {disabled}  [Boolean] - 是否禁用
 * @param {min}  [String, Number] - 最小值
 * @param {max}  [String, Number] - 最大值
 * @param {defaultValue}  [String, Number] - 默认值
 * @param {pointSize}  [String, Number] - 小数位
 * @param {intLength}  [String, Number] - 整数位
 * @param {placeholder}  [String] - 默认提示
 * @param {positive}  [Boolean] - 正数
 *
 * @event {change} 当绑定值变化时触发的事件	当前组件的值
 * @event {blur} 输入框失焦时触发
 * @event {focus} 输入框聚焦时触发
 */
import { defineComponent, ref, watch, computed } from 'vue'
export default defineComponent({
	name: 'wind-stepper',
	props: {
		value: [Number, String],
		disabled: Boolean,
		readonly: Boolean,
		integer: Boolean,
		positive: Boolean,
		min: {
			type: Number,
			default: 0
		},
		max: {
			type: Number,
			default: Infinity
		},
		pointSize: {
			type: [String, Number],
			default: 4
		},
		intLength: {
			type: [String, Number],
			default: 8
		},
		placeholder: {
			type: String,
			default: '请输入'
		},
		step: {
			type: Number,
			default: 1
		}
	},
	emits: ['update:value', 'blur', 'focus', 'change', 'overlimit', 'minus', 'plus'],
	setup (props, { emit, expose }) {
		const inputRef = ref<HTMLInputElement|null>(null)
		const currentValue = ref<number|string|undefined>(0)
		const onChange = (value: string|number) => {
			emit('update:value', value)
			emit('change', value)
		}
		const minusDisabled = computed(() => {
			return props.disabled || Number(currentValue.value) <= props.min
		})
		const plusDisabled = computed(() => {
			return props.disabled || Number(currentValue.value) >= props.max
		})
		const onStepperBtnClick = (type: string) => {
			if ((type === 'minus' && minusDisabled.value) || (type === 'plus' && plusDisabled.value)) {
				emit('overlimit', type)
				return false
			}
			const diff = type === 'minus' ? -props.step : +props.step
			const pointSize = props.integer ? 0 : props.pointSize
			const value = Math.round((Number(currentValue.value) + diff) * Math.pow(10, Number(pointSize))) / Math.pow(10, Number(pointSize))
			emit('update:value', value)
			emit('change', value)
			type === 'minus' ? emit('minus') : emit('plus')
		}
		const onBlur = (event:Event) => {
			emit('blur', event)
		}
		const onFocus = (event:Event) => {
			emit('focus', event)
		}
		const focus = () => {
			inputRef.value?.focus()
		}
		const blur = () => {
			inputRef.value?.blur()
		}
		watch(() => props.value, (val) => {
			currentValue.value = val
		}, {
			immediate: true
		})
		expose({
			focus,
			blur
		})
		return {
			inputRef,
			currentValue,
			onChange,
			onStepperBtnClick,
			onBlur,
			onFocus,
			minusDisabled,
			plusDisabled
		}
	}
})
</script>
<style lang="scss" scoped>
@import "$assets/stylus/varsty";
.wind-stepper {
	display: flex;
	flex-direction: row;
	align-items: center;
	.wind-stepper__minus,.wind-stepper__plus {
		display: flex;
		justify-content: center;
		align-items: center;
		width: 25px;
		height: 25px;
		font-size: 20px;
		border: 1px solid $fxDefaultColor;
		border-radius: 23px;
		text-align:center;
		color: $fxDefaultColor;
		&.is-disabled {
			border-color:#cccccc;
			color: #cccccc;
		}
	}
	.stepper-input {
		margin: 0 10px;
		width: 100px;
		height: 20px;
		text-align: center;
		background-color: #F9F9F9;
		line-height: 30px
	}
}
</style>
